๐ŸŽŸ๏ธ ๋™์‹œ์„ฑ ํ™˜๊ฒฝ์—์„œ DB ๋ฝ์„ ์ด์šฉํ•œ ํ‹ฐ์ผ“ ์˜ˆ์•ฝ ์‹œ์Šคํ…œ ํ…Œ์ŠคํŠธ

โœ… ํ…Œ์ŠคํŠธ ๋ชฉํ‘œ

100๊ฐœ์˜ ํ‹ฐ์ผ“์„ ๋Œ€์ƒ์œผ๋กœ ์ˆ˜์ฒœ ๋ช…์˜ ์œ ์ €๊ฐ€ ๋™์‹œ์— ์˜ˆ์•ฝ ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ,

๋™์‹œ์„ฑ ์ด์Šˆ ์—†์ด ์ •ํ™•ํžˆ 100๋ช…๊นŒ์ง€๋งŒ ์˜ˆ์•ฝ๋˜๋„๋ก ์ œ์–ด๋˜๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค.

1๏ธโƒฃ ๋ฝ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…:

    ๋™์‹œ์„ฑ ์ œ์–ด ์—†์ด reserveTicket()์„ ํ˜ธ์ถœํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„.

  • ์‹œ๋‚˜๋ฆฌ์˜ค:

    1000๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— 100๊ฐœ์˜ ํ‹ฐ์ผ“์„ ์˜ˆ์•ฝ ์‹œ๋„.

  • ๊ฒฐ๊ณผ:

    โŒ ํ…Œ์ŠคํŠธ ์‹คํŒจ โ€“ ๋™์‹œ์„ฑ ์ œ์–ด ๋ถ€์žฌ๋กœ ํ‹ฐ์ผ“ ์ˆ˜๋Ÿ‰ ์ดˆ๊ณผ ์˜ˆ์•ฝ ๋ฐœ์ƒ.

2๏ธโƒฃ-1 ๋น„๊ด€์  ๋ฝ(Pessimistic Lock)์„ ์ ์šฉํ•œ ๊ฒฝ์šฐ

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…:

    @Lock(LockModeType.PESSIMISTIC_WRITE)๋ฅผ ์ ์šฉํ•ด ๋™์‹œ์— ํ•˜๋‚˜์˜ ํ‹ฐ์ผ“๋งŒ ์ˆ˜์ • ๊ฐ€๋Šฅํ•˜๋„๋ก ์ œํ•œ.

  • ์‹œ๋‚˜๋ฆฌ์˜ค:

    10000๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— 100๊ฐœ์˜ ํ‹ฐ์ผ“์„ ์˜ˆ์•ฝ ์‹œ๋„.

  • ๊ฒฐ๊ณผ:

    โœ… ํ…Œ์ŠคํŠธ ์„ฑ๊ณต โ€“ ์ •ํ™•ํžˆ 100๋ช…๋งŒ ์˜ˆ์•ฝ๋จ.

  • ๋ฌธ์ œ์ :

    • ์‚ฌ์šฉ์ž 10,000๋ช…์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ €์žฅํ•ด ํ…Œ์ŠคํŠธ ์‹œ๊ฐ„์ด ๋งค์šฐ ๊ธธ์–ด์ง.
      • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : ๋ฒŒํฌ Insert (saveAll()) ์‚ฌ์šฉ

2๏ธโƒฃ-2 saveAll() ํ™œ์šฉํ•œ ๋ฒŒํฌ Insert ์‹œ๋„

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…:

    saveAll()๋กœ ์‚ฌ์šฉ์ž 10,000๋ช…์„ ํ•œ ๋ฒˆ์— ์ €์žฅ.

  • ๋ฌธ์ œ์ :

    • ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฌ์ „ํžˆ persist()๋ฅผ ๋ฃจํ”„ ๋Œ๋ฉฐ ํ˜ธ์ถœ โ†’ ์ฟผ๋ฆฌ N๋ฒˆ ๋ฐœ์ƒ.
    • ์ฆ‰, ์‹ค์ œ ๋ฒŒํฌ ์„ฑ๋Šฅ์€ ๊ธฐ๋Œ€๋ณด๋‹ค ๋‚ฎ์Œ.
  • ํ•ด๊ฒฐ ๋ฐฉ์•ˆ:

    Hibernate์˜ Batch Insert ์„ค์ • + EntityManager ์ง์ ‘ ์‚ฌ์šฉ.

2๏ธโƒฃ-3 EntityManager + @Transactional ๋ฐฉ์‹ ์ ์šฉ

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…:

    @PersistenceContext๋กœ ์ฃผ์ž…ํ•œ EntityManager๋ฅผ ํ†ตํ•ด flush() & clear()๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉฐ batch ์ฒ˜๋ฆฌ.

  • ๋ฌธ์ œ ๋ฐœ์ƒ: โŒ @Transactional์ด ์ ์šฉ๋˜์ง€ ์•Š์Œ

    
    @Transactional self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime
  • ์ด์œ :

    • Spring์€ AOP ๊ธฐ๋ฐ˜์œผ๋กœ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
    • ๊ฐ™์€ ํด๋ž˜์Šค ๋‚ด์—์„œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ(this) โ†’ ํ”„๋ก์‹œ ์šฐํšŒ โ†’ ํŠธ๋žœ์žญ์…˜ ์ ์šฉ ์•ˆ ๋จ

2๏ธโƒฃ-4 Self-Invocation ๋ฌธ์ œ ํ•ด๊ฒฐ: Self ์ฃผ์ž… ๊ตฌ์กฐ ๋„์ž…

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…:

    this.insertUsersInBulk() ๋Œ€์‹ , Bean์œผ๋กœ ์ฃผ์ž…๋œ ์ž์‹ (Self) ์„ ํ†ตํ•ด ํ˜ธ์ถœ

  • ๋ฌธ์ œ ๋ฐœ์ƒ: โŒ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค์— @Autowired TicketReservationServiceTest โ†’

    Could not autowire. No beans of 'TicketReservationServiceTest' type found.

  • ์ด์œ :

  • @Transactional์ด ๋ถ™์€ insertUsersInBulk()๋ฅผ ๊ฐ™์€ ํด๋ž˜์Šค ๋‚ด์—์„œ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์–ด์„œ ํŠธ๋žœ์žญ์…˜์ด ์ ์šฉ๋˜์ง€ ์•Š๊ณ , ๊ทธ ๊ฒฐ๊ณผ EntityManager๊ฐ€ ํŠธ๋žœ์žญ์…˜ ๋ฐ”๊นฅ์—์„œ ์‹คํ–‰๋˜๋ฉฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ

  • ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค๋Š” @SpringBootTest๋กœ ์‹คํ–‰๋˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์ธ Spring Bean์œผ๋กœ ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ

2๏ธโƒฃ-5 ์ตœ์ข… ํ•ด๊ฒฐ โ€“ ๋ฒŒํฌ Insert ์ „์šฉ ์„œ๋น„์Šค ๋ถ„๋ฆฌ

๐Ÿ”— ์ฝ”๋“œ ๋ณด๊ธฐ

  • ์„ค๋ช…: @Service ํด๋ž˜์Šค๋กœ InsertUsersInBulkService๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ ,

    ์—ฌ๊ธฐ์— @Transactional๊ณผ EntityManager๋ฅผ ์ ์šฉํ•ด ์˜ฌ๋ฐ”๋ฅธ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ๊ตฌํ˜„.

  • ๊ฒฐ๊ณผ: ํŠธ๋žœ์žญ์…˜ ์ •์ƒ ๋™์ž‘ + ๋น ๋ฅธ ๋Œ€์šฉ๋Ÿ‰ insert ์ฒ˜๋ฆฌ

    ํ…Œ์ŠคํŠธ ์„ฑ๊ณต

ํ…Œ์ŠคํŠธ ๋ฐฉ์‹ ๊ฒฐ๊ณผ ๋™์‹œ์„ฑ ์ œ์–ด ์„ฑ๋Šฅ ๋ฌธ์ œ ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ
๋‹จ์ˆœ ๋กœ์ง โŒ ์‹คํŒจ โŒ ์—†์Œ โŒ ๋А๋ฆผ -
Pessimistic Lock โœ… ์„ฑ๊ณต โœ… ์žˆ์Œ โŒ ๋А๋ฆผ -
saveAll() โœ… ์„ฑ๊ณต โœ… ์žˆ์Œ โš ๏ธ ๊ธฐ๋Œ€ ์ดํ•˜ -
EntityManager โŒ ์‹คํŒจ โœ… ์žˆ์Œ โœ… ๋น ๋ฆ„ โŒ ์ ์šฉ ์•ˆ ๋จ
Self ์ฃผ์ž… ๊ตฌ์กฐ โŒ ์‹คํŒจ โœ… ์žˆ์Œ โœ… ๋น ๋ฆ„ โŒ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ๋ถˆ๊ฐ€
์„œ๋น„์Šค ๋ถ„๋ฆฌ โœ… ์„ฑ๊ณต โœ… ์žˆ์Œ โœ… ๋น ๋ฆ„ โœ… ์ •์ƒ ๋™์ž‘

๐Ÿ–‹๏ธ Written by ํ™์Šน๋ฏผ


ยฉ 2025, Built with Gatsby